﻿using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Drawing.Drawing2D;

namespace Effects.GUI
{
    /// <summary>
    ///   Groups ShowWave and HScrollBar
    /// </summary>
    /// <remarks>
    ///  <para>
    ///    ShowWave class is control that visualize Wave class. It can be zoomed and scrolled. We need to have HScrollBar that controls the scrolling.
    ///    But managing this scroll bar directly in ShowWave Class would be too confusing. Therefore scroll bar is out of the ShowWave and ShowWave only handles it's events.
    ///    </para>
    ///    <para>
    ///    This cClass groups ShowWave and HScrollBar together. At creation this scrollBar is passed to thw ShowWave and enables scrolling of the ShowWave's content.
    ///  </para>
    ///   <para>
    ///    It also provides user interfaces for playing wave files (Play-, Stop-, Pause-buttons)
    ///   </para>
    /// </remarks>
    public class ShowPanel: TableLayoutPanel
    {
        #region properties.

        /// <summary>
        ///  Array of EffectBoards used to 
        /// </summary>
        private EffectBoard[] effects;

        /// <summary>
        ///  Gets or sets the effect borads to work with.
        /// </summary>
        public EffectBoard[] Effects
        {
            get { return effects; }
            set { effects = value; }
        }

        // instance of player being controlled by ShowPanel
        /// <summary>
        ///  PLayer controlled by ShowPanel
        /// </summary>
        private AudioPlayer player;

        /// <summary>
        ///  Gets current player.
        /// </summary>
        public AudioPlayer Player
        {
            get { return player; }
        }

        /// <summary>
        ///  Instance of ShowWave to display the waveform.
        /// </summary>
        private ShowWave show;

        /// <summary>
        ///  Gets ShowWave displaying the waveform
        /// </summary>
        public ShowWave Show
        {
            get { return show; }
        }
        
        // instace of HScrollBar that scrolls ShowWave
        /// <summary>
        ///  Scrolls currently displayed part fo waveform.
        /// </summary>
        private HScrollBar scrollBar;
        
        /// <summary>
        ///  Gets or sets currently played and dispayed wave
        /// </summary>
        public Wave.Wave Wav
        {
            get { return show.Wav; }
            set 
            {
                if (value != null)
                {
                    show.Wav = value;
                    PreparePlayer();
                    //BeginInvoke(preparePlayerInvoker);
                    foreach(EffectBoard b in effects)
                        b.Reset();
                }
            }
        }
       
        /// <summary>
        ///  Indicates recording mode status.
        /// </summary>
        private bool recording=false;

        /// <summary>
        ///  Gets or sets the recording mode control variable.
        /// </summary>
        public bool RecordingMode
        {
            get { return recording; }
            set
            {
                recording = value;
                if (recording)
                {
                    // show recording buttons
                    playModeButtons.Hide();
                    recordingModeButtons.Show();
                }
                else
                {
                    // show playing buttons
                    recordingModeButtons.Hide();
                    playModeButtons.Show();
                }
            }
        }

        #endregion

        #region buttons
        // buttons to control player

        /// <summary>
        ///  Play button in playing mode.
        /// </summary>
        private Button PlayMode_PlayButton;

        /// <summary>
        ///  Pause button in playing mode.
        /// </summary>
        private Button PlayMode_PauseButton;

        /// <summary>
        ///  Stop button in playing mode.
        /// </summary>
        private Button PlayMode_StopButton;

        /// <summary>
        ///  Play button in Recording mode.
        /// </summary>
        private Button RecordingMode_PlayButton;

        /// <summary>
        ///  Pause button in Recoring mode
        /// </summary>
        private Button RecordingMode_PauseButton;

        /// <summary>
        ///  Stop Button in Recording mode
        /// </summary>
        private Button RecordingMode_StopButton;

        /// <summary>
        ///  Record button
        /// </summary>
        /// <remarks>
        ///  The name obviously points out that button is availible in recording mode, but I try to keep the convention
        /// </remarks>
        private Button RecordingMode_RecordButton;

        /// <summary>
        ///  Record new button
        /// </summary>
        /// <remarks>
        ///  The name obviously points out that button is availible in recording mode, but I try to keep the convention
        /// </remarks>
        private Button RecordingMode_RecordNewButton;

        /// <summary>
        ///  Panel containing buttons in plying mode.
        /// </summary>
        private FlowLayoutPanel playModeButtons;

        /// <summary>
        ///  Panel containing button in recording mode.
        /// </summary>
        private FlowLayoutPanel recordingModeButtons;

        /// <summary>
        /// Enables or disables all the command buttons
        /// </summary>
        /// <param name="enabled"></param>
        private void EnableButtons(bool enabled)
        {
            PlayMode_PlayButton.Enabled = enabled;
            PlayMode_PauseButton.Enabled = enabled;
            PlayMode_StopButton.Enabled = enabled;

            RecordingMode_PlayButton.Enabled = enabled;
            RecordingMode_PauseButton.Enabled = enabled;
            RecordingMode_StopButton.Enabled = enabled;
            RecordingMode_RecordNewButton.Enabled = enabled;
            RecordingMode_RecordButton.Enabled = enabled;
        }

        #endregion 

        #region constructor
        // constructor and initialization stuff

        /// <summary>
        ///  Creates new instance.
        /// </summary>
        public ShowPanel()
        {
            SuspendLayout();
            InitializeComponents();
            ResumeLayout(false);
            PerformLayout();

            preparePlayerInvoker = new MethodInvoker(PreparePlayer);
        }

        /// <summary>
        ///  Prepares table layout
        /// </summary>
        private void PrepareLayout()
        {
            this.RowCount = 3;
            this.RowStyles.Add(new RowStyle(SizeType.Absolute, 50));
            this.RowStyles.Add(new RowStyle(SizeType.Absolute, 150));
            this.RowStyles.Add(new RowStyle(SizeType.Absolute, 10));
            //this.RowStyles.Add(new RowStyle(SizeType.Percent, 1));


            /*this.ColumnCount = 4;
            this.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 25F));
            this.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 25F));
            this.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 25F));
            this.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 25F));*/
            this.ColumnCount = 1;
            this.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));

        }

        /// <summary>
        ///  Prepares table and creates ShowWave and HScrollBar and links them together
        /// </summary>
        private void InitializeComponents()
        {
            this.AutoSize = true;
            this.AutoSizeMode = AutoSizeMode.GrowAndShrink;

            //this.Height = 250;
            PrepareLayout();
            show = new ShowWave(null);
            show.Dock = DockStyle.Fill;
            //show.Anchor = AnchorStyles.Right | AnchorStyles.Left;
            show.PrepareFinished += new ShowWave.PrepareFinishedDelegate(this.ShowPrepareFinished);

            scrollBar = new HScrollBar();
            scrollBar.Dock = DockStyle.Fill;
            show.ScrollBar = scrollBar;
            show.HeightChanged += new ShowWaveHeightChangedDelegate(OnShowHeightChanged);

            this.Controls.Add(show, 0, 1);
            this.Controls.Add(scrollBar, 0, 2);

            InitializeButtonPanels();

            this.Controls.Add(playModeButtons, 0, 0);
            this.Controls.Add(recordingModeButtons, 0, 0);
            recordingModeButtons.Hide();

            EnableButtons(false);
        }

        /// <summary>
        ///  Initializes pannels that groups the buttons. Buttons are devide to the groups, recording and playing, and they are
        ///  dispalyed according to the current Recording property status.
        /// </summary>
        private void InitializeButtonPanels()
        {
            // Play mode buttons
            playModeButtons = new FlowLayoutPanel();
            playModeButtons.Height = 35;
            playModeButtons.FlowDirection = FlowDirection.LeftToRight;
            playModeButtons.WrapContents = false;
            playModeButtons.AutoSize = true;

            //PlayMode_PlayButton = new Button();
            PlayMode_PlayButton = new Button();
            PlayMode_PlayButton.Image = System.Drawing.Image.FromStream(new System.IO.MemoryStream(global::GUI.Resources.Buttons.Buttons.PlayButton));
            PlayMode_PlayButton.Size = new System.Drawing.Size(PlayMode_PlayButton.Image.Width + 3, PlayMode_PlayButton.Image.Height + 3);
            PlayMode_PlayButton.BackColor = System.Drawing.Color.Transparent;
            PlayMode_PlayButton.FlatStyle = FlatStyle.Flat;
            PlayMode_PlayButton.FlatAppearance.BorderSize = 0;
            PlayMode_PlayButton.FlatAppearance.MouseOverBackColor = System.Drawing.Color.Gray;
            PlayMode_PlayButton.FlatAppearance.MouseDownBackColor = System.Drawing.Color.Black;
            PlayMode_PlayButton.ImageAlign = System.Drawing.ContentAlignment.MiddleCenter;
            //PlayMode_PlayButton.Text = "Play";
            GraphicsPath path = new GraphicsPath();
            path.AddEllipse(0, 0, PlayMode_PlayButton.Image.Width + 3, PlayMode_PlayButton.Image.Height + 3);
            PlayMode_PlayButton.Region = new System.Drawing.Region(path);
            PlayMode_PlayButton.Click += new EventHandler(this.Play_Clicked);

            PlayMode_PauseButton = new Button();
            PlayMode_PauseButton.Image = System.Drawing.Image.FromStream(new System.IO.MemoryStream(global::GUI.Resources.Buttons.Buttons.PauseButton));
            PlayMode_PauseButton.Size = new System.Drawing.Size(PlayMode_PauseButton.Image.Width + 3, PlayMode_PauseButton.Image.Height + 3);
            PlayMode_PauseButton.BackColor = System.Drawing.Color.Transparent;
            PlayMode_PauseButton.FlatStyle = FlatStyle.Flat;
            PlayMode_PauseButton.FlatAppearance.BorderSize = 0;
            PlayMode_PauseButton.FlatAppearance.MouseOverBackColor = System.Drawing.Color.Gray;
            PlayMode_PauseButton.FlatAppearance.MouseDownBackColor = System.Drawing.Color.Black;
            //PlayMode_PauseButton.Text = "Pause";
            PlayMode_PauseButton.ImageAlign = System.Drawing.ContentAlignment.MiddleCenter;
            path = new GraphicsPath();
            path.AddEllipse(0, 0, PlayMode_PauseButton.Image.Width + 3, PlayMode_PauseButton.Image.Height + 3);
            PlayMode_PauseButton.Region = new System.Drawing.Region(path);
            PlayMode_PauseButton.Click += new EventHandler(this.Pause_Clicked);

            PlayMode_StopButton = new Button();
            PlayMode_StopButton.Image = System.Drawing.Image.FromStream(new System.IO.MemoryStream(global::GUI.Resources.Buttons.Buttons.StopButton));
            PlayMode_StopButton.Size = new System.Drawing.Size(PlayMode_StopButton.Image.Width + 3, PlayMode_StopButton.Image.Height + 3);
            PlayMode_StopButton.BackColor = System.Drawing.Color.Transparent;
            PlayMode_StopButton.FlatStyle = FlatStyle.Flat;
            PlayMode_StopButton.FlatAppearance.BorderSize = 0;
            PlayMode_StopButton.FlatAppearance.MouseOverBackColor = System.Drawing.Color.Gray;
            PlayMode_StopButton.FlatAppearance.MouseDownBackColor = System.Drawing.Color.Black;
            PlayMode_StopButton.ImageAlign = System.Drawing.ContentAlignment.MiddleCenter;
            path = new GraphicsPath();
            path.AddEllipse(0, 0, PlayMode_StopButton.Image.Width + 3, PlayMode_StopButton.Image.Height + 3);
            PlayMode_StopButton.Region = new System.Drawing.Region(path);
            PlayMode_StopButton.Click += new EventHandler(this.Stop_Clicked);

            playModeButtons.Controls.Add(PlayMode_PlayButton);
            playModeButtons.Controls.Add(PlayMode_PauseButton);
            playModeButtons.Controls.Add(PlayMode_StopButton);


            // Recording mode buttons 
            recordingModeButtons = new FlowLayoutPanel();
            recordingModeButtons.FlowDirection = FlowDirection.LeftToRight;
            recordingModeButtons.WrapContents = false;
            recordingModeButtons.AutoSize = true;

            RecordingMode_PlayButton = new Button();
            RecordingMode_PlayButton.Image = System.Drawing.Image.FromStream(new System.IO.MemoryStream(global::GUI.Resources.Buttons.Buttons.PlayButton));
            PrepareButton(RecordingMode_PlayButton);
            RecordingMode_PlayButton.Click += new EventHandler(this.Play_Clicked);

            RecordingMode_PauseButton = new Button();
            RecordingMode_PauseButton.Image = System.Drawing.Image.FromStream(new System.IO.MemoryStream(global::GUI.Resources.Buttons.Buttons.PauseButton));
            PrepareButton(RecordingMode_PauseButton);
            RecordingMode_PauseButton.Click += new EventHandler(this.Pause_Clicked);

            RecordingMode_StopButton = new Button();
            RecordingMode_StopButton.Image = System.Drawing.Image.FromStream(new System.IO.MemoryStream(global::GUI.Resources.Buttons.Buttons.StopButton));
            PrepareButton(RecordingMode_StopButton);
            RecordingMode_StopButton.Click += new EventHandler(this.Stop_Clicked);

            RecordingMode_RecordButton = new Button();
            RecordingMode_RecordButton.Image = System.Drawing.Image.FromStream(new System.IO.MemoryStream(global::GUI.Resources.Buttons.Buttons.RecordButton));
            PrepareButton(RecordingMode_RecordButton);
            RecordingMode_RecordButton.Click += new EventHandler(this.Record_Clicked);


            RecordingMode_RecordNewButton = new Button();
            RecordingMode_RecordNewButton.Image = System.Drawing.Image.FromStream(new System.IO.MemoryStream(global::GUI.Resources.Buttons.Buttons.RecordNewButton));
            PrepareButton(RecordingMode_RecordNewButton);
            RecordingMode_RecordNewButton.Click += new EventHandler(this.RecordNew_Clicked);

            recordingModeButtons.Controls.Add(RecordingMode_PlayButton);
            recordingModeButtons.Controls.Add(RecordingMode_PauseButton);
            recordingModeButtons.Controls.Add(RecordingMode_StopButton);
            recordingModeButtons.Controls.Add(RecordingMode_RecordButton);
            recordingModeButtons.Controls.Add(RecordingMode_RecordNewButton);
        }

        /// <summary>
        ///  Prepares style of the given button.
        /// </summary>
        /// <param name="but"> Button to prepare </param>
        private void PrepareButton(Button but)
        {
            but.Size = new System.Drawing.Size(but.Image.Width + 3, but.Image.Height + 3);
            but.BackColor = System.Drawing.Color.Transparent;
            but.FlatStyle = FlatStyle.Flat;
            but.FlatAppearance.BorderSize = 0;
            but.FlatAppearance.MouseOverBackColor = System.Drawing.Color.Gray;
            but.FlatAppearance.MouseDownBackColor = System.Drawing.Color.Black;
            but.ImageAlign = System.Drawing.ContentAlignment.MiddleCenter;
            GraphicsPath path = new GraphicsPath();
            path.AddEllipse(0, 0, but.Image.Width + 3, but.Image.Height + 3);
            but.Region = new System.Drawing.Region(path);
        }

        #endregion

        #region showwave_events
        // handling some specific events of displayed ShowWave.

        /// <summary>
        ///  Reacts on height change of the displayed ShowWave.
        /// </summary>
        private void OnShowHeightChanged(object sender, ShowWaveHeightChangedEventAgrs e)
        {
            RowStyles[1].Height = e.Height;
        }

        /// <summary>
        ///  Enables buttons when ShowWave finishes with preparing the waveform.
        /// </summary>
        private void ShowPrepareFinished()
        {
            EnableButtons(true);
        }

        #endregion

        #region prepare_player
        // prepare new player

        /// <summary>
        ///  Invokes PreparePlayer method.
        /// </summary>
        private MethodInvoker preparePlayerInvoker;

        /// <summary>
        ///  Prepares player and sets it to the showwave
        /// </summary>
        private void PreparePlayer()
        {
            if (show.Wav != null)
            {
                this.player = new EffectStreamPlayer(this, show.Wav, effects);
                show.Player = player;
                player.EndOfFile += new EventHandler(PlayerEndOfFile);
                //EnableButtons(true);
            }
        }

        #endregion

        #region register_handlers_on_buttons
        // method allows other classes to register handlers on all buttons

        /// <summary>
        ///  Registers event handler on play button.
        /// </summary>
        /// <param name="handler"> Event handler to register </param>
        public void RegisterPlayButtonClick(EventHandler handler)
        {
            PlayMode_PlayButton.Click += handler;
            RecordingMode_PlayButton.Click += handler;

        }

        /// <summary>
        ///  Registers event handler on pause button.
        /// </summary>
        /// <param name="handler"> Event handler to register </param>
        public void RegisterPauseButtonClick(EventHandler handler)
        {
            PlayMode_PauseButton.Click += handler;
            RecordingMode_PauseButton.Click += handler;
        }

        /// <summary>
        ///  Registers event handler on stop button.
        /// </summary>
        /// <param name="handler"> Event handler to register </param>
        public void RegisterStopButtonClick(EventHandler handler)
        {
            PlayMode_StopButton.Click += handler;
            RecordingMode_StopButton.Click += handler;
        }

        /// <summary>
        ///  Registers event handler on record button.
        /// </summary>
        /// <param name="handler"> Event handler to register </param>
        public void RegisterRecordButtonClick(EventHandler handler)
        {
            RecordingMode_RecordButton.Click += handler;
        }

        /// <summary>
        ///  Registers event handler on record new button.
        /// </summary>
        /// <param name="handler"> Event handler to register </param>
        public void RegisteRecordNEWButtonClick(EventHandler handler)
        {
            RecordingMode_RecordNewButton.Click += handler;
        }

        #endregion

        #region buttons_event_handlers
        // handling clicks from the buttons

        /// <summary>
        /// PlayButton clicked event handler
        /// </summary>
        private void Play_Clicked(object sender,EventArgs e)
        {
            if (player != null)
            {
                player.Play();
                System.Threading.Thread.Sleep(200);
                show.StartTimer();
            }
        }

        /// <summary>
        /// PauseButton clicked event handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Pause_Clicked(object sender, EventArgs e)
        {
            if (player != null)
            {
                player.Pause();
                show.StopTimer();
            }
        }

        /// <summary>
        ///  StopButton event handler.
        /// </summary>
        private void Stop_Clicked(object sender, EventArgs e)
        {
            if (player != null)
            {
                player.Stop();
                show.StopTimer();

                foreach(EffectBoard b in effects)
                    b.Reset();
            }
        }

        /// <summary>
        ///  RecordButton click event handler
        /// </summary>
        private void Record_Clicked(object sender,EventArgs e)
        {
            if (player != null)
            {
                //player.Stop();
                player.Play();
                System.Threading.Thread.Sleep(200);
                show.StartTimer();
            }
        }

        /// <summary>
        ///  Record button event handler.
        /// </summary>
        private void RecordNew_Clicked(object sender, EventArgs e)
        {
            if (player != null)
            {
                player.Stop();
                player.Play();
                System.Threading.Thread.Sleep(200);
                show.StartTimer();
            }
        }

        #endregion

        #region player_event_handlers
        // handling events from player.

        /// <summary>
        ///  Simulates stop at the end fo file.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void PlayerEndOfFile(object sender, EventArgs e)
        {
            if(InvokeRequired)
                BeginInvoke(new MethodInvoker(Stop));
            else
                Stop();
        }

        /// <summary>
        ///  Stops the player.
        /// </summary>
        public void Stop()
        {
            if (recording)
                this.RecordingMode_StopButton.PerformClick();
            else
                PlayMode_StopButton.PerformClick();
        }

        #endregion

    }
}
